<script lang="ts" setup>
import { computed, ref, nextTick, useTemplateRef } from 'vue';
import { useRouter } from 'vue-router';
import { useFetch } from '@/home/hooks/fetch';
import { useAsyncData } from '@/home/hooks/async-data';
import { useTitleForClient } from '@/home/hooks/browser';
import SidePanel, { type EngagementData } from './components/SidePanel.vue';
import { useI18n } from 'vue-i18n';
import markdownIt from 'markdown-it';
import SanitizeHtml from '@/common/components/sanitize-html/index.vue';
import Author from './components/Author.vue';
import Tag from '@/home/components/Tag.vue';
import Comment from './components/Comment.vue';
import { getShortDate } from '@/home/utils/date';

import Prism from 'virtual:prismjs';

const props = defineProps({
  id: {
    type: String,
    default: '',
  },
  pageType: {
    type: String,
    default: 'detail',
  },
});

const { $fetch } = useFetch();
const router = useRouter();
const { setTitle } = useTitleForClient();
const { t } = useI18n();
const engagement = ref<EngagementData>();
const defaultTitle = props.pageType === 'preview' ? t('home.explore.journalism.previewTitle') : t('home.explore.journalism.title');
const contentRef = useTemplateRef('contentEl');
const sidePanelRef = useTemplateRef('sidePanelEl');
const commentSectionRef = useTemplateRef('commentSectionEl');

const generateTitle = (title: string) => `${title} - ${defaultTitle}`;

const renderHighlight = () => {
  nextTick(() => {
    const el = contentRef.value?.getElement();

    if (el) {
      Prism.highlightAllUnder(el);
    }
  });
};

const { data: detail } = useAsyncData(
  'explore:journalism:detail',
  () => $fetch(props.pageType === 'preview' ? '/information/preview' : '/information/view', { data: { id: props.id } }),
  {
    cache: false,
    watch: [() =>  props.id],
    onAfterHandle({ handleSuccess, serverContext }) {
      if (serverContext) {
        if (handleSuccess && detail.value) {
          serverContext.title = generateTitle(detail.value.informationTitle);
          serverContext.description = detail.value.informationMsg;
          serverContext.keywords = detail.value.informationKeywords;
        }
        else {
          // 如果请求出错直接服务器重定向到 404 页面
          serverContext.redirect = '/404';
        }
      }
      else {
        if (handleSuccess && detail.value) {
          setTitle(generateTitle(detail.value.informationTitle));
          renderHighlight();
        }
        else {
          router.replace('/404');
        }
      }
    },
  },
);

const { data: engagementDetail } = useAsyncData(
  'explore:journalism:detail:engagement',
  () => $fetch<EngagementData>('/information/like/num', { data: { informationId: props.id } }),
  {
    cache: false,
    watch: [() =>  props.id],
    onAfterHandle({ handleSuccess }) {
      if (handleSuccess) {
        engagement.value = { ...engagementDetail.value };
      }
    },
  },
)

const labelList = computed(() => {
  return detail.value?.labelVOList || [];
});

const handleChange = (data: EngagementData) => {
  engagement.value = { ...data };
}

const getRenderedContent = (type: number, text: string) => {
  if (type == 1) {
    const md = markdownIt({
      breaks: true,
      linkify: false,
      typographer: false,
      html: true,
      highlight: function(str, lang) {
        if (lang) {
          return `<pre class="language-${lang}"><code>${str.replace(/</g, '&lt;').replace(/>/g, '&gt;')}</code></pre>`;
        }

        return '';
      },
    });

    return md.render(text ?? '');
  }
  else {
    return text;
  }
}

const handleCommentChange = () => {
  sidePanelRef.value?.refresh();
}

const handleSidePanelClick = (who: string) => {
  if (who == 'comment') {
    commentSectionRef.value?.scrollIntoView({
      behavior: 'smooth',
      block: 'start',
    });
  }
}
</script>

<template>
  <main class="page-explore-detail pt-280">
    <section class="min-h-1000 rounded-4 bg-white pb-40 shadow-[0_1px_6px_0_rgba(0,0,0,0.04)]">
      <div class="container" v-if="detail">
        <div class="flex">
          <SidePanel
            :id="props.id"
            class="w-245 pt-40"
            :enable-comment="detail.openComments == 1"
            @change="handleChange"
            @click="handleSidePanelClick"
            ref="sidePanelEl"
          />

          <div class="relative w-710 pt-201">
            <div class="absolute left-0 right-0 top--256 h-417">
              <img class="block size-full rounded-4 object-contain" :src="detail.coverUrl" :alt="detail.informationTitle">
            </div>

            <h1 class="break-anywhere text-24 color-hex-292929 font-medium leading-40">
              {{ props.pageType === 'preview' ? $t('home.explore.journalism.preview') : '' }}{{ detail.informationTitle }}
            </h1>

            <div class="mt-40 flex-y-center justify-between">
              <div>
                <Author
                  :id="detail.authorInfo.id"
                  :avatar="detail.authorInfo.photo"
                  :name="detail.authorInfo.username"
                  :nickname="detail.authorInfo.nickname"
                  :description="detail.authorInfo.profile"
                  :article="detail.authorInfo.informationCount"
                  :follower="detail.authorInfo.fansNum"
                  :following="detail.authorInfo.attentionNum"
                  :followed="detail.authorInfo.isFollow"
                  v-if="detail.authorInfo"
                />
              </div>
              <div class="text-12 color-hex-8b8b8b font-normal leading-22">
                <span class="mr-8" v-if="detail.publishTime">
                  {{ $t('home.explore.journalism.public', { date: getShortDate(detail.publishTime) }) }}
                </span>
                <span>
                  {{ $t('home.explore.journalism.view', { total: engagement?.informationViews ?? 0 }) }}
                  ·
                  {{ $t('home.explore.journalism.like', { total: engagement?.informationLikeCount ?? 0 }) }}
                  ·
                  {{ $t('home.explore.journalism.favorite', { total: engagement?.informationCollections ?? 0 }) }}
                </span>
              </div>
            </div>

            <SanitizeHtml
              class="detail-content line-numbers mt-40 min-h-500 break-anywhere color-#292929"
              :class="[detail.textType == 1 ? 'markdown' : 'rich-text']"
              :value="getRenderedContent(detail.textType, detail.informationContent)"
              :data-prismjs-copy="$t('common.prismjs.copy')"
              :data-prismjs-copy-error="$t('common.prismjs.copyError')"
              :data-prismjs-copy-success="$t('common.prismjs.copySuccess')"
              ref="contentEl"
            />

            <div class="mt-40" v-if="detail?.allowReprinting != 1">
              <hr class="border-#F7F7F7">
              <p class="mt-40 text-12 text-#8B8B8B leading-22">
                {{ $t('home.explore.journalism.copyRight1', { name: detail.authorInfo.nickname }) }}<br>
                {{ $t('home.explore.journalism.copyRight2') }}
              </p>
            </div>

            <div class="mt-40 flex gap-x-8 border-hex-f7f7f7" v-if="labelList.length">
              <template v-for="item in labelList" :key="item.labelId">
                <Tag
                  :id="item.labelId"
                  :name="item.labelName"
                  class="block h-22 cursor-pointer rounded-11 bg-hex-f7f7f7 px-8 py-3 text-center text-12 color-hex-8b8b8b font-normal leading-16"
                  blank
                />
              </template>
            </div>
          </div>
        </div>
      </div>
    </section>

    <section class="mx-auto mt-40 max-w-710" ref="commentSectionEl" v-if="detail?.openComments == 1">
      <Comment :id="props.id" @change="handleCommentChange" />
    </section>
  </main>
</template>

<style lang="scss" scoped>
.page-explore-detail {
  .detail-content:deep() {
    h1 {
      font-size: 22px;
    }

    h2 {
      font-size: 20px;
    }

    h3 {
      font-size: 18px;
    }

    h1,
    h2 {
      margin-top: 48px;
      font-weight: 500;
    }

    ol,
    ul,
    menu {
      margin-top: 1em;
      margin-bottom: 1em;
      padding-left: 40px;
    }

    ol {
      list-style: decimal;
    }

    ul {
      list-style: disc;
    }

    p,
    section {
      margin-top: 1em;
      margin-bottom: 1em;
      font-weight: 400;
      font-size: 16px;
      line-height: 24px;
    }

    img {
      max-width: 100%;
    }

    table {
      td {
        border-color: gray;
        border-width: 1px;
      }
    }

    pre {
      overflow-x: auto;
    }
  }

  .detail-content.markdown:deep() {
    table {
      width: 100%;
    }
  }
}
</style>
